Modern microprocessors and software compilers employ many techniques to help increase the speed with which software executes. Examples of techniques that are used to help speed up the execution speed of processors include speculative execution of code, reuse buffers that hold instances of previously executed software for later reuse, and branch target buffers (BTB) that try to predict whether branches are taken.
Research is ongoing in areas of modeling processor performance. See Derek B. Noonburg & John P. Shen, “Theoretical Modeling of Superscalar Processor performance,” MICRO-27, November 1994; and Derek B. Noonburg & John P. Shen, “A Framework for Statistical Modeling of Superscalar Processor Performance,” Proceedings of the Third International Symposium on High Performance Computer Architecture, February 1997.
Some modern processors employ dynamic optimization that attempt to more fully utilize the resources of the processor. Approaches include: control speculation using predicate promotion; load speculation using advanced or speculative advanced load or prefetch load; and static hints for branch direction or cache placement for loads. Many of these approaches can result in “non-essential” code used for optimization being intermixed with “essential” application level software code.
The essential code is typically created by a compiler from the application level software code. The essential code is what determines the logical correctness of the resulting program. The non-essential code is also typically created by a compiler, but it differs from the essential code in that it is a result of optimizations and other compile-time operations, rather than the applications level software program.
Intermixing of non-essential code and essential code creates competition for processor resources between the two types of code. Although a net increase in execution speed can result from the above techniques, if the competition for resources is fierce, the above techniques can slow down the execution of the application level software.
In addition to static intermixing of non-essential code with essential code, some known dynamic optimization techniques reorder machine instructions in an attempt to more fully utilize processor resources. For example, dynamic optimizers can introduce non-essential prefetch instructions and intermix them with original essential code, and/or reorder the original essential code based on run-time dynamic profiling feedback. This can lead to problems, in part because reordering of machine instructions may draw out latent “bugs” in the software, thereby sacrificing the logical correctness of the application level software code. One example of a latent bug is an uninitialized variable. The bug may not be detected in the original code because of a fortuitous register assignment, but when instructions are reordered, the bug may manifest itself.
For the reasons stated above, and for other reasons stated below which will become apparent to those skilled in the art upon reading and understanding the present specification, there is a need in the art for an alternate method and apparatus for combining essential code and non-essential code.